﻿using System;
using System.Collections.ObjectModel;
using System.Runtime.InteropServices;
using EasyHook;
using MassPokerTool.Infrastructure.Hooking.Data;
using MassPokerTool.Infrastructure.Hooking.Filters;

namespace MassPokerTool.Infrastructure.Hooking.Hooks
{
    public class BeginPaintHook : HookBase
    {
        [UnmanagedFunctionPointer(CallingConvention.StdCall, CharSet = CharSet.Unicode, SetLastError = true)]
        public delegate int DBeginPaint(int hwnd, ref PlatformInvoke.Paintstruct lpPaint);

        private readonly ReadOnlyCollection<IBeginPaintFilter> _filters;

        public BeginPaintHook(ReadOnlyCollection<IBeginPaintFilter> filters)
        {
            _filters = filters;
        }

        protected override LocalHook CreateHookInternal(object callback)
        {
            var hook = LocalHook.Create(
                LocalHook.GetProcAddress("user32.dll", "BeginPaint"),
                new DBeginPaint(BeginPaintHooked),
                callback);
            hook.ThreadACL.SetExclusiveACL(new[] { 0 });
            return hook;
        }

        private int BeginPaintHooked(int hwnd, ref PlatformInvoke.Paintstruct lppaint)
        {
            var callback = (IQueueableEntryPoint)HookRuntimeInfo.Callback;
            try
            {
                foreach (var filter in _filters)
                {
                    IHookData hookData;
                    if (filter.Match(hwnd, ref lppaint, out hookData))
                    {
                        lock (callback.Queue)
                            callback.Queue.Enqueue(hookData);
                    }
                }
            }
            catch (Exception e)
            {
                lock (callback.Queue)
                {
                    callback.Queue.Enqueue(new ErrorHookData() { Exception = e });
                }
            }
            return PlatformInvoke.BeginPaint(hwnd, ref lppaint);
        }
    }
}
